// tvcontroller.go
// 封装 Go2TV 投屏核心功能为 TVController 结构体
// 需要配合 github.com/alexballas/go2tv 的相关包使用

package main

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	"github.com/alexballas/go2tv/devices"
	"github.com/alexballas/go2tv/httphandlers"
	"github.com/alexballas/go2tv/soapcalls"
	"github.com/alexballas/go2tv/soapcalls/utils"
)

// 设备结构体
type Device struct {
	Model string
	URL   string
}

// 投屏控制器结构体
type TVController struct {
	dmrURL    string
	server    *httphandlers.HTTPserver
	tvdata    *soapcalls.TVPayload
	ctx       context.Context
	cancelCtx context.CancelFunc
}

// 构造函数
func NewTVController() *TVController {
	ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	return &TVController{
		ctx:       ctx,
		cancelCtx: cancel,
	}
}

// 获取设备列表
func (c *TVController) GetDevices() ([]Device, error) {
	deviceList, err := devices.LoadSSDPservices(1)
	if err != nil {
		return nil, fmt.Errorf("failed to list devices: %w", err)
	}

	var devicesSlice []Device
	for model, url := range deviceList {
		devicesSlice = append(devicesSlice, Device{Model: model, URL: url})
	}

	return devicesSlice, nil
}

// 设置目标设备
func (c *TVController) SetDevice(rawURL string) error {
	if _, err := url.ParseRequestURI(rawURL); err != nil {
		return fmt.Errorf("invalid device URL: %w", err)
	}
	c.dmrURL = rawURL
	return nil
}

// 投屏指定视频文件
func (c *TVController) CastVideo(filePath string) error {
	absPath, err := filepath.Abs(filePath)
	if err != nil {
		return err
	}

	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		return fmt.Errorf("file not found: %s", filePath)
	}

	mfile, err := os.Open(absPath)
	if err != nil {
		return err
	}
	defer mfile.Close()

	mediaType, err := utils.GetMimeDetailsFromFile(mfile)
	if err != nil {
		return err
	}

	isSeek := true // 默认不转码，允许跳转

	// 初始化 TVPayload
	c.tvdata, err = soapcalls.NewTVPayload(&soapcalls.Options{
		DMR:       c.dmrURL,
		Media:     absPath,
		Mtype:     mediaType,
		Transcode: false, // 默认不转码
		Seek:      isSeek,
	})
	if err != nil {
		return err
	}

	// 启动 HTTP 服务
	c.server = httphandlers.NewServer(c.tvdata.ListenAddress())
	serverStarted := make(chan error)

	// dummy screen for EmitMsg and Fini
	go func() {
		c.server.StartServer(serverStarted, absPath, "", c.tvdata, &dummyScreen{ctxCancel: c.cancelCtx})
	}()

	if err := <-serverStarted; err != nil {
		return err
	}

	return c.tvdata.SendtoTV("Play1")
}

// 停止投屏
func (c *TVController) StopCast() error {
	if c.tvdata == nil {
		return errors.New("no active casting session")
	}

	err := c.tvdata.SendtoTV("Stop")
	if c.server != nil {
		c.server.StopServer()
	}
	c.server = nil
	c.tvdata = nil

	if c.cancelCtx != nil {
		c.cancelCtx()
	}

	return err
}

// 是否正在投屏
func (c *TVController) IsCasting() bool {
	return c.tvdata != nil
}

// 辅助结构体（Dummy Screen）
type dummyScreen struct {
	ctxCancel context.CancelFunc
}

func (s *dummyScreen) EmitMsg(msg string) {
	fmt.Println(msg)
}

func (s *dummyScreen) Fini() {
	fmt.Println("exiting..")
	s.ctxCancel()
}
